package com.ydl.shopping.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ydl.shopping.core.dto.MetaDTO;
import com.ydl.shopping.core.entity.TreeSelect;
import com.ydl.shopping.domain.TbMenu;
import com.ydl.shopping.domain.TbRole;
import com.ydl.shopping.domain.TbUser;
import com.ydl.shopping.mapper.TbMenuMapper;
import com.ydl.shopping.service.ITbMenuService;
import com.ydl.shopping.service.ITbRoleService;
import com.ydl.shopping.service.ITbUserService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
@Service
public class TbMenuServiceImpl extends ServiceImpl<TbMenuMapper, TbMenu> implements ITbMenuService {
    private final ITbUserService tbUserService;

    private final ITbRoleService tbRoleService;

    public TbMenuServiceImpl(@Lazy ITbUserService tbUserService, @Lazy ITbRoleService tbRoleService) {
        this.tbUserService = tbUserService;
        this.tbRoleService = tbRoleService;
    }

    @Override
    public QueryWrapper<TbMenu> queryWrapper(TbMenu entity) {
        QueryWrapper<TbMenu> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(entity.getName())) {
            queryWrapper.like("name", entity.getName());
        }
        if (entity.getParentId() != null) {
            queryWrapper.eq("parent_id", entity.getParentId());
        }
        if (entity.getIsVisible() != null) {
            queryWrapper.eq("is_visible", entity.getIsVisible());
        }
        if (entity.getNodeType() != null) {
            queryWrapper.eq("node_type", entity.getNodeType());
        }
        if (entity.getStatus() != null) {
            queryWrapper.eq("status", entity.getStatus());
        }
        return queryWrapper;
    }

    @Override
    public String saveMenu(TbMenu tbMenu) {
        Long parentId = tbMenu.getParentId();
        if (parentId != null && parentId > 0) {
            TbMenu parentMenu = getById(parentId);
            if (parentMenu == null) {
                return "父级菜单不存在";
            }
        }
        Integer nodeType = tbMenu.getNodeType();
        if (parentId != null && parentId > 0) {
            int level = 0;
            if (nodeType == null || nodeType == 1) {
                level = getMenuLevel(parentId, level);
            }
            tbMenu.setLevel(level);
        }
        boolean result = save(tbMenu);
        if (result) {
            tbRoleService.saveSuperAdmin(tbMenu.getId());
        }
        return result ? null : "操作失败";
    }

    /**
     * 获取菜单层级
     *
     * @param parentId 父级ID
     * @param level 初始层级
     * @return 层级
     */
    private int getMenuLevel(Long parentId, int level) {
        level += 1;
        TbMenu tbMenu = getById(parentId);
        if (tbMenu != null && tbMenu.getParentId() != null && tbMenu.getParentId() > 0) {
            level = getMenuLevel(tbMenu.getParentId(), level);
        }
        return level;
    }

    @Override
    public int getMenuMaxLevel() {
        return query().select("MAX(level) as level").one().getLevel();
    }

    @Override
    public List<TbMenu> tree(TbMenu tbMenu) {
        // 设置菜单节点类型
        tbMenu.setNodeType(1);
        // 获取数据
        List<TbMenu> list = list(queryWrapper(tbMenu));
        if (list.isEmpty()) {
            return Collections.emptyList();
        }
        // 过滤父级数据
        List<TbMenu> parentList = list.stream().filter(item -> {
            Long parentId = tbMenu.getParentId();
            if (parentId == null) {
                parentId = 0L;
            }
            return parentId.equals(item.getParentId());
        }).collect(Collectors.toList());

        List<TbMenu> menuList = new ArrayList<>();

        for (TbMenu parentEntity : parentList) {
            List<TbMenu> buildChildrenTree = buildChildrenTree(parentEntity);
            parentEntity.setChildren(buildChildrenTree);
            menuList.add(parentEntity);
        }

        return menuList;
    }

    private List<TbMenu> buildChildrenTree(TbMenu tbMenu) {
        ArrayList<TbMenu> childrenTree = new ArrayList<>();
        Long parentId = tbMenu.getId();

        List<TbMenu> childrenList = query().eq("parent_id", parentId).list();
        if (childrenList != null && !childrenList.isEmpty()) {
            for (TbMenu menu : childrenList) {
                List<TbMenu> buildChildrenTree = buildChildrenTree(menu);
                menu.setChildren(buildChildrenTree);
                childrenTree.add(menu);
            }
        }
        return childrenTree;
    }

    @Override
    public List<TbMenu> router(Long userId) {
        TbUser tbUser = tbUserService.getById(userId);
        List<Long> roleIds = tbUser.getRoleIds();

        // 获取用户菜单IDs
        Set<Long> menuIDs = new HashSet<>();
        for (Long roleId : roleIds) {
            TbRole tbRole = tbRoleService.getById(roleId);
            List<Long> menuIds = tbRole.getMenuIds();
            menuIDs.addAll(menuIds);
        }

        // 获取菜单集合
        List<TbMenu> tbMenus = listByIds(menuIDs);
        tbMenus = tbMenus.stream()
                .filter(sysMenu -> sysMenu.getStatus() == 1 && sysMenu.getIsVisible() == 1)
                .sorted(Comparator.comparing(TbMenu::getSort)).collect(Collectors.toList());

        List<TbMenu> parentMenu = new ArrayList<>();
        int maxLevel = getMenuMaxLevel();
        for (int i = 0; i <= maxLevel; i++) {
            int finalI = i;
            parentMenu = tbMenus.stream().filter(sysMenu -> sysMenu.getParentId() == finalI).sorted(Comparator.comparing(TbMenu::getSort)).collect(Collectors.toList());
            if (!parentMenu.isEmpty()) {
                break;
            }
        }

        if (parentMenu.isEmpty()) {
            return Collections.emptyList();
        }

        // 根级菜单
        ArrayList<TbMenu> tree = new ArrayList<>();
        for (TbMenu menu : parentMenu) {
            if (!menuIDs.contains(menu.getId())) {
                continue;
            }
            List<TbMenu> buttons = parentMenu.stream()
                    .filter(sysMenu -> sysMenu.getParentId()
                            .equals(menu.getId()) && sysMenu.getNodeType() == 2 && sysMenu.getStatus() == 1 && sysMenu.getIsVisible() == 1).sorted(Comparator.comparing(TbMenu::getSort)).collect(Collectors.toList());
            if (!buttons.isEmpty()) {
                MetaDTO metaDTO = new MetaDTO();
                metaDTO.setTitle(menu.getName());
                metaDTO.setButtons(buttons);
                menu.setMeta(JSONUtil.toJsonStr(metaDTO));
            }
            List<TbMenu> children = getChildren(menuIDs, tbMenus, menu);
            menu.setChildren(children);
            tree.add(menu);
        }

        return tree;
    }

    /**
     * 获取子菜单
     *
     * @param sysMenus 原始菜单
     * @param sysMenu 父级菜单
     * @return 子菜单列表
     */
    private List<TbMenu> getChildren(Set<Long> menuIds, List<TbMenu> sysMenus, TbMenu sysMenu) {
        List<TbMenu> childrenList = new ArrayList<>();

        List<TbMenu> menuList = sysMenus.stream().filter(menu -> menu.getParentId().equals(sysMenu.getId()) && menu.getNodeType() == 1).collect(Collectors.toList());

        for (TbMenu menu : menuList) {
            if (!menuIds.contains(menu.getId())) {
                continue;
            }
            List<TbMenu> buttonList = sysMenus.stream().filter(m -> m.getParentId().equals(menu.getId()) && m.getNodeType() == 2).collect(Collectors.toList());
            if (!buttonList.isEmpty()) {
                MetaDTO metaDTO = new MetaDTO();
                metaDTO.setTitle(menu.getName());
                metaDTO.setButtons(buttonList);
                menu.setMeta(JSONUtil.toJsonStr(metaDTO));
            }
            List<TbMenu> children = getChildren(menuIds, sysMenus, menu);
            menu.setChildren(children);

            childrenList.add(menu);
        }

        return childrenList;
    }

    @Override
    public List<TreeSelect> select(Long userId) {
        List<TbMenu> router = router(userId);
        if (router != null && !router.isEmpty()) {
            return buildSelect(router);
        }
        return Collections.emptyList();
    }

    private List<TreeSelect> buildSelect(List<TbMenu> tbMenus) {
        List<TreeSelect> treeSelects = new ArrayList<>();
        for (TbMenu tbMenu : tbMenus) {
            TreeSelect treeSelect = new TreeSelect();
            treeSelect.setId(tbMenu.getId());
            treeSelect.setLabel(tbMenu.getName());
            treeSelect.setValue(tbMenu.getId().toString());
            if (tbMenu.getChildren() != null && !tbMenu.getChildren().isEmpty()) {
                List<TreeSelect> children = buildSelect(tbMenu.getChildren());
                treeSelect.setChildren(children);
            }
            treeSelects.add(treeSelect);
        }
        return treeSelects;
    }
}
